﻿using System.Collections;
using System.Text;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using System.Diagnostics;
using SixLabors.ImageSharp.Drawing.Processing;
using static MyWatermark.BlockGenerator;
namespace MyWatermark
{
    public class SpatialBlock
    {
        public int BlockId { get; set; }
        public Rectangle Position { get; set; }
        public float TextureLevel { get; set; } // 纹理强度值
        public List<int> AssociatedBits { get; set; } // 关联的bit索引
    }

    public class BlockGenerator
    {
        private const int BASE_BLOCK_SIZE = 64;
        private const int OVERLAP_STEP = 16;
        private const float TEXTURE_THRESHOLD = 0.65f;

        public Dictionary<Point, BlockMetadata> GenerateRedundantBlocks(Image<Bgra32> sourceImage)
        {
            // 第一阶段：生成基础分块网格
            var baseGrid = GenerateBaseGrid(sourceImage);

            // 第二阶段：纹理特征分析
            var textureMap = BuildTextureMap(sourceImage);

            // 第三阶段：动态添加冗余块
            var redundantBlocks = AddRedundantBlocks(sourceImage, textureMap);

            // 第四阶段：构建空间索引
            return BuildSpatialIndex(baseGrid, redundantBlocks, sourceImage);
        }

        #region 核心子方法实现
        private List<BlockMetadata> GenerateBaseGrid(Image<Bgra32> image)
        {
            var blocks = new List<BlockMetadata>();
            int rows = (image.Height - BASE_BLOCK_SIZE) / OVERLAP_STEP + 1;
            int cols = (image.Width - BASE_BLOCK_SIZE) / OVERLAP_STEP + 1;

            for (int y = 0; y <= image.Height - BASE_BLOCK_SIZE; y += OVERLAP_STEP)
            {
                for (int x = 0; x <= image.Width - BASE_BLOCK_SIZE; x += OVERLAP_STEP)
                {
                    var rect = new Rectangle(x, y, BASE_BLOCK_SIZE, BASE_BLOCK_SIZE);
                    blocks.Add(new BlockMetadata
                    {
                        Position = rect,
                        IsRedundant = false,
                        TextureLevel = 0f
                    });
                }
            }
            return blocks;
        }

        private float[,] BuildTextureMap(Image<Bgra32> image)
        {
            var map = new float[image.Width, image.Height];
            int kernelSize = 5;

            // 预处理图像数据到内存数组
            var luminanceData = PreprocessToLuminanceArray(image);

            // 并行计算梯度图（不依赖PixelAccessor）
            Parallel.For(0, image.Height, y =>
            {
                for (int x = 0; x < image.Width; x++)
                {
                    if (IsBorderPixel(x, y, image.Width, image.Height, kernelSize))
                    {
                        map[x, y] = 0;
                        continue;
                    }

                    // 使用预处理后的数据计算梯度
                    float gx = CalculateGradientX(luminanceData, x, y);
                    float gy = CalculateGradientY(luminanceData, x, y);
                    map[x, y] = MathF.Sqrt(gx * gx + gy * gy);
                }
            });

            NormalizeTextureMap(map);
            return map;
        }

        private List<BlockMetadata> AddRedundantBlocks(Image<Bgra32> image, float[,] textureMap)
        {
            var redundantBlocks = new List<BlockMetadata>();
            int scanStep = BASE_BLOCK_SIZE / 2;

            for (int y = 0; y < image.Height - BASE_BLOCK_SIZE; y += scanStep)
            {
                for (int x = 0; x < image.Width - BASE_BLOCK_SIZE; x += scanStep)
                {
                    float textureSum = 0;
                    for (int i = 0; i < BASE_BLOCK_SIZE; i++)
                        for (int j = 0; j < BASE_BLOCK_SIZE; j++)
                            textureSum += textureMap[x + i, y + j];

                    float textureAvg = textureSum / (BASE_BLOCK_SIZE * BASE_BLOCK_SIZE);

                    if (textureAvg > TEXTURE_THRESHOLD)
                    {
                        redundantBlocks.Add(new BlockMetadata
                        {
                            Position = new Rectangle(x, y, BASE_BLOCK_SIZE, BASE_BLOCK_SIZE),
                            IsRedundant = true,
                            TextureLevel = textureAvg
                        });

                        // 超高纹理区域添加偏移块
                        if (textureAvg > 0.8f)
                        {
                            redundantBlocks.Add(new BlockMetadata
                            {
                                Position = new Rectangle(x + 8, y + 8, BASE_BLOCK_SIZE, BASE_BLOCK_SIZE),
                                IsRedundant = true,
                                TextureLevel = textureAvg
                            });
                        }
                    }
                }
            }
            return redundantBlocks;
        }
        #endregion

        #region 辅助方法
        private Dictionary<Point, BlockMetadata> BuildSpatialIndex(
            List<BlockMetadata> baseBlocks,
            List<BlockMetadata> redundantBlocks,
            Image<Bgra32> sourceImage)
        {
            return baseBlocks.Concat(redundantBlocks)
                .Where(b => IsValidBlock(b.Position, sourceImage.Size)) // 新增校验
                .ToDictionary(b =>
                    new Point(b.Position.X + b.Position.Width / 2,
                             b.Position.Y + b.Position.Height / 2));
        }

        private bool IsValidBlock(Rectangle rect, Size imageSize)
        {
            return rect.Right <= imageSize.Width &&
                   rect.Bottom <= imageSize.Height &&
                   rect.Width == BASE_BLOCK_SIZE &&
                   rect.Height == BASE_BLOCK_SIZE;
        }

        private float Convolve(Span<Bgra32> row, int x, int y,
                             float[,] kernel,
                             PixelAccessor<Bgra32> accessor)
        {
            float result = 0;
            int radius = kernel.GetLength(0) / 2;

            for (int i = -radius; i <= radius; i++)
            {
                for (int j = -radius; j <= radius; j++)
                {
                    var pixel = accessor.GetRowSpan(y + j)[x + i];
                    float luminance = 0.299f * pixel.R + 0.587f * pixel.G + 0.114f * pixel.B;
                    result += luminance * kernel[i + radius, j + radius];
                }
            }
            return result;
        }

        private void NormalizeTextureMap(float[,] map)
        {
            float maxVal = 0;
            foreach (var val in map)
                if (val > maxVal) maxVal = val;

            Parallel.For(0, map.GetLength(1), y =>
            {
                for (int x = 0; x < map.GetLength(0); x++)
                    map[x, y] /= maxVal;
            });
        }

        private float[,] PreprocessToLuminanceArray(Image<Bgra32> image)
        {
            var luminance = new float[image.Width, image.Height];

            image.ProcessPixelRows(accessor =>
            {
                for (int y = 0; y < accessor.Height; y++)
                {
                    Span<Bgra32> row = accessor.GetRowSpan(y);
                    for (int x = 0; x < row.Length; x++)
                    {
                        luminance[x, y] = 0.299f * row[x].R +
                                          0.587f * row[x].G +
                                          0.114f * row[x].B;
                    }
                }
            });
            return luminance;
        }

        private static bool IsBorderPixel(int x, int y, int width, int height, int kernelSize)
        {
            int radius = kernelSize / 2;
            return x < radius || x >= width - radius ||
                   y < radius || y >= height - radius;
        }

        private float CalculateGradientX(float[,] luminance, int x, int y)
        {
            float sum = 0;
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    sum += luminance[x + i, y + j] * SobelKernelX[i + 1, j + 1];
                }
            }
            return sum;
        }

        private float CalculateGradientY(float[,] luminance, int x, int y)
        {
            float sum = 0;
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    sum += luminance[x + i, y + j] * SobelKernelY[i + 1, j + 1];
                }
            }
            return sum;
        }
        #endregion

        #region 内核定义与数据结构
        private static readonly float[,] SobelKernelX =
        {
        { -1, 0, 1 },
        { -2, 0, 2 },
        { -1, 0, 1 }
    };

        private static readonly float[,] SobelKernelY =
        {
        { -1, -2, -1 },
        {  0,  0,  0 },
        {  1,  2,  1 }
    };

        public class BlockMetadata
        {
            public Rectangle Position { get; set; }
            public bool IsRedundant { get; set; }
            public float TextureLevel { get; set; }
            public List<int> AssociatedBits { get; } = new List<int>();
        }
        #endregion

        #region 可视化方法（ImageSharp实现）
        public Image<Bgra32> VisualizeBlocks(Image<Bgra32> image,
                                           IEnumerable<BlockMetadata> blocks)
        {
            var options = new DrawingOptions
            {
                GraphicsOptions = new GraphicsOptions
                {
                    Antialias = false,
                    ColorBlendingMode = PixelColorBlendingMode.Normal
                }
            };

            image.Mutate(ctx =>
            {
                foreach (var block in blocks)
                {
                    var color = block.IsRedundant ? Color.Red : Color.LimeGreen;
                    ctx.Draw(options, color, 2, block.Position);
                }
            });

            return image;
        }

        #endregion

    }

    public static class WatermarkCore
    {
        // 添加随机种子参数
        public const int RandomSeed = 20230825; // 固定种子保证可重复性

        private const int BlockSize = 8;

        #region 块生成顺序
        public static List<Point> GenerateBlockOrder(Image<Bgra32> image, int widthBlocks, int heightBlocks)
        {
            //return GetConsistentBlockOrder(image).Keys
            //    .OrderBy(p => p.Y * image.Width + p.X) // 光栅扫描顺序
            //    .ToList(); 

            // 小尺寸图像使用螺旋顺序
            if (widthBlocks * heightBlocks < 10000)
                return GenerateSpiralOrder(widthBlocks, heightBlocks);

            // 大尺寸使用随机顺序（保留抗裁剪优势）
            return GenerateRandomOrder(widthBlocks, heightBlocks);
        }

        public static List<Point> GenerateSpiralOrder(int widthBlocks, int heightBlocks)
        {
            var spiralOrder = new List<Point>();
            int top = 0, bottom = heightBlocks - 1;
            int left = 0, right = widthBlocks - 1;
            int direction = 0; // 0:右, 1:下, 2:左, 3:上

            while (top <= bottom && left <= right)
            {
                switch (direction)
                {
                    case 0: // Right
                        for (int x = left; x <= right; x++)
                            spiralOrder.Add(new Point(x, top));
                        top++;
                        break;
                    case 1: // Down
                        for (int y = top; y <= bottom; y++)
                            spiralOrder.Add(new Point(right, y));
                        right--;
                        break;
                    case 2: // Left
                        for (int x = right; x >= left; x--)
                            spiralOrder.Add(new Point(x, bottom));
                        bottom--;
                        break;
                    case 3: // Up
                        for (int y = bottom; y >= top; y--)
                            spiralOrder.Add(new Point(left, y));
                        left++;
                        break;
                }
                direction = (direction + 1) % 4;
            }
            return spiralOrder;
        }

        public static List<Point> GenerateRandomOrder(int widthBlocks, int heightBlocks)
        {
            var blocks = new List<Point>();
            for (int y = 0; y < heightBlocks; y++)
                for (int x = 0; x < widthBlocks; x++)
                    blocks.Add(new Point(x, y));

            // 使用固定种子的随机洗牌
            var rand = new Random(RandomSeed);
            return blocks.OrderBy(b => rand.Next()).ToList();


        }

        public static Dictionary<Point, BlockMetadata> GetConsistentBlockOrder(Image<Bgra32> image)
        {
            // 使用与GenerateRedundantBlocks相同的生成逻辑
            var generator = new BlockGenerator();
            var blocks = generator.GenerateRedundantBlocks(image);

            // 按坐标排序保证确定性
            return blocks;
        }

        #endregion

        #region 选择嵌入的域
        // 动态位置选择算法（需与提取端一致）
        private static List<Point> SelectEmbedDomain(int blockX, int blockY, Random rand)
        {
            List<Point> result = new List<Point>();

            var candidates = new[] {
               (5,5), (6,6), (7,7), (5,7),
            (7,5), (6,7), (7,6), (5,6)
            };
            for (int i = 0; i < 1; i++)
            {
                // 根据块内容动态选择位置
                int index = (blockX % 2) switch
                {
                    0 => rand.Next(0, 4),
                    _ => rand.Next(4, 8)
                };
                result.Add(new Point(candidates[index].Item1, candidates[index].Item2));

            }


            //result.Add(new Point(5, 5));

            return result;
        }

        // 改进的位置选择（中心优先）
        private static List<Point> SelectEmbedDomain(int blockX, int blockY, int totalX, int totalY, Random rand)
        {
            bool isCentral = blockX > totalX / 4 && blockX < totalX * 3 / 4
                          && blockY > totalY / 4 && blockY < totalY * 3 / 4;

            if (isCentral)
            {
                return new List<Point> { new(5, 5), new(6, 6) }; // 中心固定位置
            }
            else
            {
                var candidates = new[] { (5, 7), (7, 5), (6, 7), (7, 6) };
                int index = rand.Next(candidates.Length);
                return new List<Point> { new(candidates[index].Item1, candidates[index].Item2) };
            }
        }
        #endregion

        #region 强度

        // 修改强度计算
        public static double CalculateAdaptiveStrength(double[,] block)
        {
            // 限制方差计算范围
            double avg = block.Cast<double>().Average();
            double variance = Math.Min(block.Cast<double>().Average(v => Math.Pow(v - avg, 2)), 0.05);

            // 调整强度曲线
            double baseStrength = 0.5 + 0.5 * (1 - Math.Exp(-variance * 50));

            // 亮度补偿因子
            double luminanceFactor = 0.3 + 0.7 * avg;

            // 最终强度限制在[0.5, 2.0]
            return Math.Clamp(baseStrength * luminanceFactor, 0.5, 2.0);
        }

        private static readonly double[,] perceptualWeight =
{
    {0.02, 0.04, 0.06, 0.08, 0.12, 0.16, 0.20, 0.24},
    {0.04, 0.07, 0.10, 0.13, 0.16, 0.20, 0.24, 0.28},
    {0.06, 0.10, 0.14, 0.18, 0.22, 0.26, 0.30, 0.34},
    {0.08, 0.13, 0.18, 0.23, 0.28, 0.33, 0.38, 0.43},
    {0.12, 0.16, 0.22, 0.28, 0.34, 0.40, 0.46, 0.52},
    {0.16, 0.20, 0.26, 0.33, 0.40, 0.47, 0.54, 0.61},
    {0.20, 0.24, 0.30, 0.38, 0.46, 0.54, 0.62, 0.70},
    {0.24, 0.28, 0.34, 0.43, 0.52, 0.61, 0.70, 0.79}
};

        public static double GetPerceptualStrength(int i, int j, double baseStrength)
        {
            return baseStrength * (1 - perceptualWeight[i, j]);
        }
        #endregion

        #region 分块
        public static double[,] GetBlock(double[,] channel, int x0, int y0, int size)
        {
            int width = channel.GetLength(0);
            int height = channel.GetLength(1);
            var block = new double[size, size];

            // 预计算边界值（线程安全）
            int xMax = width > 0 ? width - 1 : 0;
            int yMax = height > 0 ? height - 1 : 0;

            // 仅对大尺寸区块启用并行（根据实测调整阈值）
            //if (size >= 64) // 经验值：当区块尺寸≥64时并行收益明显
            if (width * height >= 1000)
            {
                Parallel.For(0, size, dstY =>
                {
                    ProcessRow(channel, block, x0, y0, xMax, yMax, dstY, size);
                });
            }
            else
            {
                for (int dstY = 0; dstY < size; dstY++)
                {
                    ProcessRow(channel, block, x0, y0, xMax, yMax, dstY, size);
                }
            }
            return block;
        }

        // 线程安全的行处理单元
        private static void ProcessRow(
            double[,] channel,
            double[,] block,
            int x0, int y0,
            int xMax, int yMax,
            int dstY, int size)
        {
            int srcY = y0 + dstY;
            srcY = srcY < 0 ? 0 : srcY > yMax ? yMax : srcY;

            for (int dstX = 0; dstX < size; dstX++)
            {
                int srcX = x0 + dstX;
                srcX = (uint)srcX > (uint)xMax ? (srcX < 0 ? 0 : xMax) : srcX;
                block[dstX, dstY] = channel[srcX, srcY];
            }
        }

        public static void SetBlock(double[,] channel, double[,] block, int x0, int y0)
        {
            for (int y = 0; y < BlockSize; y++)
            {
                for (int x = 0; x < BlockSize; x++)
                {
                    int destX = Math.Clamp(x0 + x, 0, channel.GetLength(0) - 1);
                    int destY = Math.Clamp(y0 + y, 0, channel.GetLength(1) - 1);
                    channel[destX, destY] = block[x, y];
                }
            }
        }

        #endregion


        #region 嵌入和提取
        // 嵌入水印
        public static byte[] Embed(List<bool> watermark, byte[] hostImage)
        {
            using var image = Image.Load<Bgra32>(hostImage);
            YuvData yuv = ColorConverter.RgbToYuv(image);

            // 计算总块数
            int widthBlocks = (yuv.Width + BlockSize - 1) / BlockSize;
            int heightBlocks = (yuv.Height + BlockSize - 1) / BlockSize;

            var watermarkBlockOrder = GenerateBlockOrder(image, widthBlocks, heightBlocks);
            EmbedWatermark(watermark, yuv, watermarkBlockOrder);

            using var output = ColorConverter.YuvToRgb(yuv);
            long saveFileProcessTime;
            return GetBytesFromImage(output, Image.DetectFormat(hostImage), hostImage.Length, out saveFileProcessTime);
        }

        public static byte[] Embed(List<bool> watermark, byte[] hostImage, out long saveFileProcessTime)
        {
            using var image = Image.Load<Bgra32>(hostImage);
            YuvData yuv = ColorConverter.RgbToYuv(image);

            // 计算总块数
            int widthBlocks = (yuv.Width + BlockSize - 1) / BlockSize;
            int heightBlocks = (yuv.Height + BlockSize - 1) / BlockSize;

            var watermarkBlockOrder = GenerateBlockOrder(image, widthBlocks, heightBlocks);
            EmbedWatermark(watermark, yuv, watermarkBlockOrder);

            using var output = ColorConverter.YuvToRgb(yuv);

            return GetBytesFromImage(output, Image.DetectFormat(hostImage), hostImage.Length, out saveFileProcessTime);
        }

        public static byte[] GetBytesFromImage(Image<Bgra32> img, IImageFormat originalFormat, long hostImageSize, out long processTime)
        {
            //bool useTempFile = false;
            //string tempFolderPath = AppContext.BaseDirectory + @$"tempWaterFiles";
            //if (!Directory.Exists(tempFolderPath))
            //{
            //    Directory.CreateDirectory(tempFolderPath);
            //}
            //string tempFilePath = tempFolderPath + @$"\{FileNameGenerator.GenerateShortName()}";
            //if (hostImageSize > 1024 * 1024 * 5)
            //{
            //    useTempFile = false;
            //}

            Stopwatch sw = new Stopwatch();
            sw.Start();
            using var ms = new MemoryStream();
            switch (originalFormat.Name)
            {
                case "JPEG":
                    var jpegOptions = new JpegEncoder
                    {
                        Quality = 100,                // 推荐质量参数
                        ColorType = JpegEncodingColor.YCbCrRatio444,  // 更高的压缩率
                        SkipMetadata = true

                    };
                    //if (useTempFile) img.Save(tempFilePath, jpegOptions);
                    //else img.Save(ms, jpegOptions);
                    img.Save(ms, jpegOptions);
                    break;

                case "PNG":
                    var pngOptions = new PngEncoder
                    {
                        CompressionLevel = PngCompressionLevel.DefaultCompression,
                        ColorType = PngColorType.RgbWithAlpha,
                        SkipMetadata = true
                    };

                    //if (useTempFile) img.Save(tempFilePath, pngOptions);
                    //else img.Save(ms, pngOptions);
                    img.Save(ms, pngOptions);
                    break;

                default:
                    // 其他格式保持默认编码
                    //if (useTempFile) img.Save(tempFilePath);
                    //else img.Save(ms, originalFormat);
                    img.Save(ms, originalFormat);
                    break;
            }

            var result = ms.ToArray();
            sw.Stop();
            processTime = sw.ElapsedMilliseconds;
            return result;

            //if (useTempFile)
            //{
            //    var result = File.ReadAllBytes(tempFilePath);
            //    File.Delete(tempFilePath);
            //    return result;
            //}
            //else
            //{
            //    var result = ms.ToArray();
            //    return result;
            //}
        }



        public static void EmbedWatermark(List<bool> watermark, YuvData yuv, List<Point> blockOrder)
        {
            int bitIndex = 0;
            foreach (var blockCoord in blockOrder)
            {

                int x = blockCoord.X * BlockSize;
                int y = blockCoord.Y * BlockSize;

                if (bitIndex >= watermark.Count)
                    break;

                // 计算当前块坐标
                int blockX = blockCoord.X;
                int blockY = blockCoord.Y;



                double[,] block = GetBlock(yuv.Y, x, y, BlockSize);
                DctTransformer.Dct(block);



                var AdaptiveStrength = CalculateAdaptiveStrength(block);


                int widthBlocks = (yuv.Width + BlockSize - 1) / BlockSize;
                int heightBlocks = (yuv.Height + BlockSize - 1) / BlockSize;

                var positions = SelectEmbedDomain(blockX, blockY, new Random(RandomSeed));

                foreach (var pos in positions)
                {
                    if (bitIndex >= watermark.Count) break;
                    double strength = GetPerceptualStrength(pos.X, pos.Y, AdaptiveStrength);
                    // 分散嵌入到多个系数
                    block[pos.X, pos.Y] += watermark[bitIndex] ? strength : -strength;
                    //bitIndex++;

                }
                bitIndex++;



                DctTransformer.Idct(block);
                SetBlock(yuv.Y, block, x, y);

            }


        }


        public static byte[]? Embed(List<bool> watermark, byte[] hostImage, bool returnDebugInfo, out DebugInfo debugInfo, out long saveFileProcessTime)
        {
            byte[] watermarked = null;
            debugInfo = null;
            saveFileProcessTime = 0;
            try
            {
                watermarked = Embed(watermark, hostImage, out saveFileProcessTime);
                var bitArrayLength = watermark.Count;
                // 提取水印
                BitArray extracted = Extract(watermarked);


                if (returnDebugInfo)
                {
                    if (watermark.Count != extracted.Length)
                    {
                        debugInfo = new DebugInfo()
                        {
                            Note = "解析结果长度不对"
                        };
                    }
                    else
                    {
                        // 计算误码率
                        int errors = 0;
                        for (int i = 0; i < watermark.Count; i++)

                            if (watermark[i] != extracted[i]) errors++;

                        debugInfo = new DebugInfo()
                        {
                            ErrorBits = errors,
                            TotalBits = bitArrayLength,
                            Psnr = TestTools.CalculatePsnr(hostImage, watermarked)
                        };
                    }


                }
            }
            catch (Exception ex)
            {

            }

            return watermarked;
        }


        //改进的提取方法
        public static BitArray Extract(byte[] imageData)
        {
            //// 第一阶段：提取尺寸头
            //var (originalWidth, originalHeight) = ExtractSizeHeader(imageData);

            //// 调整到原始尺寸
            //using var resizedImage = ResizeToOriginal(imageData, originalWidth, originalHeight);

            using var img = Image.Load<Bgra32>(imageData);
            // 第二阶段：完整提取
            return ExtractCore(img);
        }


        #endregion

        // 新增辅助方法：解析长度头
        private static int BinaryToDataLength(BitArray headerBits)
        {
            try
            {
                byte[] bytes = new byte[4];
                for (int i = 0; i < 32; i += 8)
                {
                    string byteStr = string.Join("", headerBits.Cast<bool>().Skip(i).Take(8)
                                              .Select(b => b ? "1" : "0"));
                    bytes[i / 8] = Convert.ToByte(byteStr, 2);
                }
                return BitConverter.ToInt32(bytes, 0);
            }
            catch
            {
                return 0;
            }
        }

        // 提取水印
        // 核心提取逻辑
        private static BitArray ExtractCore(Image<Bgra32> image)
        {
            YuvData yuv = ColorConverter.RgbToYuv(image);

            var bits = new List<bool>();
            int totalBitsNeeded = 32;
            bool headerParsed = false;
            int dataLength = 0;

            // 计算总块数
            int widthBlocks = (yuv.Width + BlockSize - 1) / BlockSize;
            int heightBlocks = (yuv.Height + BlockSize - 1) / BlockSize;
            // 使用相同的块顺序生成逻辑
            var blockOrder = GenerateBlockOrder(image, widthBlocks, heightBlocks);

            foreach (var blockCoord in blockOrder)
            {
                int x = blockCoord.X * BlockSize;
                int y = blockCoord.Y * BlockSize;
                // 计算当前块坐标
                int blockX = blockCoord.X;
                int blockY = blockCoord.Y;

                double[,] block = GetBlock(yuv.Y, x, y, BlockSize);
                DctTransformer.Dct(block);

                var positions = SelectEmbedDomain(blockX, blockY, new Random(RandomSeed));

                //投票决策
                //int[] votes = new int[positions.Count];
                Dictionary<int, int> votes = new Dictionary<int, int>();
                votes.Add(0, 0);
                votes.Add(1, 0);
                foreach (var pos in positions)
                {
                    bool candidateBit = (block[pos.X, pos.Y] > 0) ? true : false;
                    votes[candidateBit ? 1 : 0]++;
                }

                // 第一阶段：提取长度头
                if (!headerParsed)
                {


                    bits.Add(votes[1] >= votes[0]);
                    if (bits.Count >= 32)
                    {
                        dataLength = BinaryToDataLength(new BitArray(bits.Take(32).ToArray()));
                        totalBitsNeeded = 32 + dataLength * 8;
                        headerParsed = true;
                    }
                }
                // 第二阶段：提取数据
                else
                {
                    if (bits.Count >= totalBitsNeeded) break;
                    bits.Add(votes[1] >= votes[0]);
                }

                if (bits.Count >= totalBitsNeeded) break;
            }


            return new BitArray(bits.Take(totalBitsNeeded).ToArray());
        }

        // 新增：尺寸调整方法
        private static Image<Bgra32> ResizeToOriginal(byte[] imageData, int targetWidth, int targetHeight)
        {
            using var image = Image.Load<Bgra32>(imageData);
            image.Mutate(ctx => ctx.Resize(targetWidth, targetHeight, new NearestNeighborResampler()));
            return image.Clone();
        }

        public static List<bool> TextToBinaryWithHeader(string text)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(text);
            List<bool> binaryList = new List<bool>();

            // 添加4字节（32位）长度头
            byte[] lengthHeader = BitConverter.GetBytes(bytes.Length);
            foreach (byte b in lengthHeader)
            {
                binaryList.AddRange(Convert.ToString(b, 2).PadLeft(8, '0').Select(c => c == '1'));
            }

            // 添加文本数据
            foreach (byte b in bytes)
            {
                binaryList.AddRange(Convert.ToString(b, 2).PadLeft(8, '0').Select(c => c == '1'));
            }



            return binaryList;
        }

        // 提取时读取长度头
        public static string BinaryToTextWithHeader(BitArray bitArray)
        {
            try
            {
                List<bool> binaryList = new List<bool>();
                for (int i = 0; i < bitArray.Length; i++)
                {
                    binaryList.Add(bitArray[i]);
                }

                // 读取前32位（4字节）长度头
                byte[] lengthBytes = new byte[4];
                for (int i = 0; i < 32; i += 8)
                {
                    string byteStr = string.Join("", binaryList.GetRange(i, 8).Select(b => b ? "1" : "0"));
                    lengthBytes[i / 8] = Convert.ToByte(byteStr, 2);
                }
                int length = BitConverter.ToInt32(lengthBytes, 0);

                // 读取后续数据

                List<byte> dataBytes = new List<byte>();
                for (int i = 32; i < 32 + length * 8; i += 8)
                {
                    string byteStr = string.Join("", binaryList.GetRange(i, 8).Select(b => b ? "1" : "0"));
                    dataBytes.Add(Convert.ToByte(byteStr, 2));
                }
                return Encoding.UTF8.GetString(dataBytes.ToArray());
            }
            catch
            {
                return "";
            }
        }


        public static void test()
        {
            int lowFreqRadius = 7; // 定义低频区域半径（左上角5×5）
            string imgFilePath = @"D:\ywd\work\ncs\新水印的尝试\MyWatermark\gitee\pic\outergreen.jpg";
            string outFilePath = @"D:\ywd\work\ncs\新水印的尝试\MyWatermark\gitee\pic\outergreenTest.jpg";

            int fixStrength = 100;
            string msg = "hel";

            var msgBites = BitConverterEx.StringToBits(msg);
            var msgBitLength = msgBites.Length;

            var mgs2 = BitConverterEx.BitsToString(msgBites);
            var embedPositions = new[] { (2, 2), (3, 1), (1, 3) }; // 低频区域


            var image = Image.Load<Bgra32>(imgFilePath);
            var yuvData = ColorConverter.RgbToYuv(image);
            DctTransformer.Dct(yuvData.Y);
            var w = yuvData.Y.GetUpperBound(0) + 1;
            var h = yuvData.Y.GetUpperBound(1) + 1;

            var bitIndex = 0;
            for (int x = 0; x < Math.Min(w, lowFreqRadius); x++)
            {
                if (bitIndex >= msgBitLength) break;
                for (int y = 0; y < Math.Min(h, lowFreqRadius); y++)
                {
                    if (bitIndex >= msgBitLength) break;
                    yuvData.Y[x, y] += msgBites[bitIndex] ? fixStrength : -fixStrength;
                    bitIndex++;
                }
            }


            DctTransformer.Idct(yuvData.Y);
            var img2 = ColorConverter.YuvToRgb(yuvData);

            img2.Save(outFilePath);



            {

                List<bool> result = new List<bool>();
                //var img = Image.Load<Bgra32>(outFilePath);
                var yuvData2 = ColorConverter.RgbToYuv(img2);
                DctTransformer.Dct(yuvData2.Y);
                var w2 = yuvData2.Y.GetUpperBound(0) + 1;
                var h2 = yuvData2.Y.GetUpperBound(1) + 1;

                var bitIndex2 = 0;
                for (int x = 0; x < Math.Min(w2, lowFreqRadius); x++)
                {
                    if (bitIndex2 >= msgBitLength) break;
                    for (int y = 0; y < Math.Min(h2, lowFreqRadius); y++)
                    {
                        if (bitIndex2 >= msgBitLength) break;
                        result.Add(yuvData2.Y[x, y] - yuvData.Y[x, y] > fixStrength / 2);
                        bitIndex2++;

                    }
                }

                string resultMsg = BitConverterEx.BitsToString(result);

            }
        }

    }
}
